import { def } from "./utils.js";
//获取数组的原型
const arrayProto = Array.prototype;
//Array.prototype为原型创建arrayMethods对象，并将该对象暴露出去
//之后数组调用这7个方法时，让数组调用arrayMethods对象上我们已经进行重写的这7个方法
export const arrayMethods = Object.create(arrayProto);
const methodName = [
  "push",
  "pop",
  "shift",
  "unshift",
  "splice",
  "sort",
  "reverse",
];
methodName.forEach(function (method) {
  //备份原来的方法
  const original = arrayProto[method];
  // 定义新的方法：在arrayMethods对象上进行
  def(
    arrayMethods,
    method,
    function (...args) {
      //执行原来的方法，实现push等这7个方法的功能
      //不能直接original()调用，因为这样调用的话original的上下文是window对象
      //需要使用apply改变original的上下文为调用该函数的数组
      //因为push这7个方法中有些方法（例如pop，splice）含有返回值
      //所以我们需要利用result储存一下返回值，之后再把result return出去
      const result = original.apply(this, args);

      //监听到数组改变之后就可以执行一些我们需要增加的操作了

      //数组肯定不是最高层,比如obj.c是数组，则obj一定不是数组，第一层遍历obj对象时，已经给c属性（就是这个数组）添加了__ob__属性。
      //所以我们拿到这个数组的__ob__
      //这里的this指的就是调用该函数的数组，因为该函数绑定到了arrayMethods对象上的push等7个属性上，而arrayMethods对象被我们变成了数组的原型
      //所以我们对数组执行push等7个方法时，实际就是数组调用了它arrayMethods原型上对应得方法，也即是该函数
      //所以该函数的this指向是调用该函数的数组
      const ob = this.__ob__;
      let inserted;
      switch (method) {
        case "push":
        case "unshift":
          inserted = args;
          break;

        case "splice":
          //splice格式是splice(下标，数量，插入的新项)
          inserted = args.slice(2);
          break;
      }
      if (inserted) {
        ob.observeArray(inserted);
      }
      //触发依赖
      ob.dep.notify();
      //   console.log("调用了我们改写的7方法");

      return result;
    },
    false
  );
});
